<!DOCTYPE html><html><head>
<title>fileutil_traverse - file utilities</title>
<style type="text/css"><!--
    HTML {
	background: 	#FFFFFF;
	color: 		black;
    }
    BODY {
	background: 	#FFFFFF;
	color:	 	black;
    }
    DIV.doctools {
	margin-left:	10%;
	margin-right:	10%;
    }
    DIV.doctools H1,DIV.doctools H2 {
	margin-left:	-5%;
    }
    H1, H2, H3, H4 {
	margin-top: 	1em;
	font-family:	sans-serif;
	font-size:	large;
	color:		#005A9C;
	background: 	transparent;
	text-align:		left;
    }
    H1.doctools_title {
	text-align: center;
    }
    UL,OL {
	margin-right: 0em;
	margin-top: 3pt;
	margin-bottom: 3pt;
    }
    UL LI {
	list-style: disc;
    }
    OL LI {
	list-style: decimal;
    }
    DT {
	padding-top: 	1ex;
    }
    UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
	font:		normal 12pt/14pt sans-serif;
	list-style:	none;
    }
    LI.doctools_section, LI.doctools_subsection {
	list-style: 	none;
	margin-left: 	0em;
	text-indent:	0em;
	padding: 	0em;
    }
    PRE {
	display: 	block;
	font-family:	monospace;
	white-space:	pre;
	margin:		0%;
	padding-top:	0.5ex;
	padding-bottom:	0.5ex;
	padding-left:	1ex;
	padding-right:	1ex;
	width:		100%;
    }
    PRE.doctools_example {
	color: 		black;
	background: 	#f5dcb3;
	border:		1px solid black;
    }
    UL.doctools_requirements LI, UL.doctools_syntax LI {
	list-style: 	none;
	margin-left: 	0em;
	text-indent:	0em;
	padding:	0em;
    }
    DIV.doctools_synopsis {
	color: 		black;
	background: 	#80ffff;
	border:		1px solid black;
	font-family:	serif;
	margin-top: 	1em;
	margin-bottom: 	1em;
    }
    UL.doctools_syntax {
	margin-top: 	1em;
	border-top:	1px solid black;
    }
    UL.doctools_requirements {
	margin-bottom: 	1em;
	border-bottom:	1px solid black;
    }
--></style>
</head>
<!-- Generated from file 'traverse.man' by tcllib/doctools with format 'html'
   -->
<!-- fileutil_traverse.n
   -->
<body><hr> [
   <a href="../../../../../../../../home">Tcllib Home</a>
&#124; <a href="../../../../toc.html">Main Table Of Contents</a>
&#124; <a href="../../../toc.html">Table Of Contents</a>
&#124; <a href="../../../../index.html">Keyword Index</a>
&#124; <a href="../../../../toc0.html">Categories</a>
&#124; <a href="../../../../toc1.html">Modules</a>
&#124; <a href="../../../../toc2.html">Applications</a>
 ] <hr>
<div class="doctools">
<h1 class="doctools_title">fileutil_traverse(n) 0.6 tcllib &quot;file utilities&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>fileutil_traverse - Iterative directory traversal</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">OPTIONS</a></li>
<li class="doctools_section"><a href="#section3">Warnings and Incompatibilities</a></li>
<li class="doctools_section"><a href="#section4">Bugs, Ideas, Feedback</a></li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#category">Category</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">Tcl 8.3</b></li>
<li>package require <b class="pkgname">fileutil::traverse <span class="opt">?0.6?</span></b></li>
<li>package require <b class="pkgname">fileutil</b></li>
<li>package require <b class="pkgname">control</b></li>
</ul>
<ul class="doctools_syntax">
<li><a href="#1"><b class="cmd">::fileutil::traverse</b> <span class="opt">?<i class="arg">objectName</i>?</span> <i class="arg">path</i> <span class="opt">?<i class="arg">option</i> <i class="arg">value</i>...?</span></a></li>
<li><a href="#2"><b class="cmd">$traverser</b> <b class="method">command</b> <span class="opt">?<i class="arg">arg arg ...</i>?</span></a></li>
<li><a href="#3"><b class="cmd">$traverser</b> <b class="method">files</b></a></li>
<li><a href="#4"><b class="cmd">$traverser</b> <b class="method">foreach</b> <i class="arg">filevar</i> <i class="arg">script</i></a></li>
<li><a href="#5"><b class="cmd">$traverser</b> <b class="method">next</b> <i class="arg">filevar</i></a></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>This package provides objects for the programmable traversal of
directory hierarchies.
The main command exported by the package is:</p>
<dl class="doctools_definitions">
<dt><a name="1"><b class="cmd">::fileutil::traverse</b> <span class="opt">?<i class="arg">objectName</i>?</span> <i class="arg">path</i> <span class="opt">?<i class="arg">option</i> <i class="arg">value</i>...?</span></a></dt>
<dd><p>The command creates a new traversal object with an associated global
Tcl command whose name is <i class="arg">objectName</i>. This command may be used
to invoke various operations on the traverser.
If the string <b class="const">%AUTO%</b> is used as the <i class="arg">objectName</i> then a
unique name will be generated by the package itself.</p>
<p>Regarding the recognized options see section <span class="sectref"><a href="#section2">OPTIONS</a></span>. Note
that all these options can be set only during the creation of the
traversal object. Changing them later is not possible and causes
errors to be thrown if attempted.</p>
<p>The object command has the following general form:</p>
<dl class="doctools_definitions">
<dt><a name="2"><b class="cmd">$traverser</b> <b class="method">command</b> <span class="opt">?<i class="arg">arg arg ...</i>?</span></a></dt>
<dd><p><i class="arg">Command</i> and its <i class="arg">arg</i>uments determine the exact behavior of
the object.</p></dd>
</dl></dd>
</dl>
<p>The following commands are possible for traversal objects:</p>
<dl class="doctools_definitions">
<dt><a name="3"><b class="cmd">$traverser</b> <b class="method">files</b></a></dt>
<dd><p>This method is the most highlevel one provided by traversal
objects. When invoked it returns a list containing the names of all
files and directories matching the current configuration of the
traverser.</p></dd>
<dt><a name="4"><b class="cmd">$traverser</b> <b class="method">foreach</b> <i class="arg">filevar</i> <i class="arg">script</i></a></dt>
<dd><p>The highlevel <b class="method">files</b> method (see above) is based on this
mid-level method. When invoked it finds all files and directories
matching per the current configuration and executes the <i class="arg">script</i>
for each path. The current path under consideration is stored in the
variable named by <i class="arg">filevar</i>. Both variable and script live / are
executed in the context of the caller of the method. In the method
<b class="method">files</b> the script simply saves the found paths into the list
to return.</p></dd>
<dt><a name="5"><b class="cmd">$traverser</b> <b class="method">next</b> <i class="arg">filevar</i></a></dt>
<dd><p>This is the lowest possible interface to the traverser, the core all
higher methods are built on. When invoked it returns a boolean value
indicating whether it found a path matching the current configuration
(<b class="const">True</b>), or not (<b class="const">False</b>). If a path was found it is
stored into the variable named by <i class="arg">filevar</i>, in the context of the
caller.</p>
<p>The <b class="method">foreach</b> method simply calls this method in a loop
until it returned <b class="const">False</b>. This method is exposed so that we are
also able to incrementally traverse a directory hierarchy in an
event-based manner.</p>
<p>Note that the traverser does follow symbolic links, except when
doing so would cause it to enter a link-cycle. In other words, the
command takes care to <em>not</em> lose itself in infinite loops upon
encountering circular link structures. Note that even links which are
not followed will still appear in the result.</p></dd>
</dl>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">OPTIONS</a></h2>
<dl class="doctools_options">
<dt><b class="option">-prefilter</b> command_prefix</dt>
<dd><p>This callback is executed for directories. Its result determines if
the traverser recurses into the directory or not. The default is to
always recurse into all directories. The callback is invoked with a
single argument, the <em>absolute</em> path of the directory, and has to
return a boolean value, <b class="const">True</b> when the directory passes the
filter, and <b class="const">False</b> if not.</p></dd>
<dt><b class="option">-filter</b> command_prefix</dt>
<dd><p>This callback is executed for all paths. Its result determines if the
current path is a valid result, and returned by <b class="method">next</b>. The
default is to accept all paths as valid. The callback is invoked with
a single argument, the <em>absolute</em> path to check, and has to
return a boolean value, <b class="const">True</b> when the path passes the filter,
and <b class="const">False</b> if not.</p></dd>
<dt><b class="option">-errorcmd</b> command_prefix</dt>
<dd><p>This callback is executed for all paths the traverser has trouble
with. Like being unable to change into them, get their status,
etc. The default is to ignore any such problems. The callback is
invoked with a two arguments, the <em>absolute</em> path for which the
error occured, and the error message. Errors thrown by the filter
callbacks are handled through this callback too. Errors thrown by the
error callback itself are not caught and ignored, but allowed to pass
to the caller, i.e. however invoked the <b class="method">next</b>. Any other
results from the callback are ignored.</p></dd>
</dl>
</div>
<div id="section3" class="doctools_section"><h2><a name="section3">Warnings and Incompatibilities</a></h2>
<dl class="doctools_definitions">
<dt><b class="const">0.4.4</b></dt>
<dd><p>In this version the traverser's broken system for handling symlinks
was replaced with one working correctly and properly enumerating all
the legal non-cyclic paths under a base directory.</p>
<p>While correct this means that certain pathological directory
hierarchies with cross-linked sym-links will now take about O(n**2)
time to enumerate whereas the original broken code managed O(n) due to
its brokenness.</p>
<p>A concrete example and extreme case is the &quot;<b class="file">/sys</b>&quot;
hierarchy under Linux where some hundred devices exist under both
&quot;<b class="file">/sys/devices</b>&quot; and &quot;<b class="file">/sys/class</b>&quot; with the two sub-hierarchies
linking to the other, generating millions of legal paths to enumerate.
The structure, reduced to three devices, roughly looks like</p>
<pre class="doctools_example">
	/sys/class/tty/tty0 --&gt; ../../dev/tty0
	/sys/class/tty/tty1 --&gt; ../../dev/tty1
	/sys/class/tty/tty2 --&gt; ../../dev/tty1
	/sys/dev/tty0/bus
	/sys/dev/tty0/subsystem --&gt; ../../class/tty
	/sys/dev/tty1/bus
	/sys/dev/tty1/subsystem --&gt; ../../class/tty
	/sys/dev/tty2/bus
	/sys/dev/tty2/subsystem --&gt; ../../class/tty
</pre>
<p>When having to handle such a pathological hierarchy it is
recommended to use the <b class="option">-prefilter</b> option to prevent the
traverser from following symbolic links, like so:</p>
<pre class="doctools_example">
    package require fileutil::traverse
    proc NoLinks {fileName} {
        if {[string equal [file type $fileName] link]} {
            return 0
        }
        return 1
    }
    fileutil::traverse T /sys/devices -prefilter NoLinks
    T foreach p {
        puts $p
    }
    T destroy
</pre>
</dd>
</dl>
</div>
<div id="section4" class="doctools_section"><h2><a name="section4">Bugs, Ideas, Feedback</a></h2>
<p>This document, and the package it describes, will undoubtedly contain
bugs and other problems.
Please report such in the category <em>fileutil</em> of the
<a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>.
Please also report any ideas for enhancements you may have for either
package and/or documentation.</p>
<p>When proposing code changes, please provide <em>unified diffs</em>,
i.e the output of <b class="const">diff -u</b>.</p>
<p>Note further that <em>attachments</em> are strongly preferred over
inlined patches. Attachments can be made by going to the <b class="const">Edit</b>
form of the ticket immediately after its creation, and then using the
left-most button in the secondary navigation bar.</p>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../../../index.html#directory_traversal">directory traversal</a>, <a href="../../../../index.html#traversal">traversal</a></p>
</div>
<div id="category" class="doctools_section"><h2><a name="category">Category</a></h2>
<p>Programming tools</p>
</div>
</div></body></html>
